from django.core.exceptions import ObjectDoesNotExist
from django.db import transaction
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework.exceptions import ValidationError
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework_simplejwt.authentication import JWTAuthentication

from .models import Paper, PaperQuestion
from .serializers import PaperSerializer, PaperDetailSerializer
from ..QuestionManagement.models import Questions
from ..UserManagement.models import User
from ..utils.pageNumberPagination import CustomPageNumberPagination
from ..utils.response_utils import api_response, ResponseCode


class CreatePaper(APIView):
    """
        创建试卷
    """
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

    @swagger_auto_schema(
        operation_description="创建试卷接口",
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            required=['exam_name', 'exam_description', 'exam_duration', 'questions'],
            properties={
                'exam_name': openapi.Schema(type=openapi.TYPE_STRING, description='考试名称'),
                'exam_description': openapi.Schema(type=openapi.TYPE_STRING, description='考试说明'),
                'exam_duration': openapi.Schema(type=openapi.TYPE_INTEGER, description='考试时长'),
                'user_id': openapi.Schema(type=openapi.TYPE_STRING, description='创建人'),
                'is_random': openapi.Schema(type=openapi.TYPE_INTEGER, description='是否随机排序'),
                'questions': openapi.Schema(
                    type=openapi.TYPE_ARRAY,
                    items=openapi.Schema(
                        type=openapi.TYPE_OBJECT,
                        properties={
                            'question': openapi.Schema(type=openapi.TYPE_STRING, description='试题ID'),
                            'score': openapi.Schema(type=openapi.TYPE_NUMBER, description='分值'),
                        },
                    ),
                    description='试题数组，每个试题包含试题ID和分值',
                )
            },
        ),
        responses={
            200: openapi.Response(
                '创建成功！',
                openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'exam_name': openapi.Schema(type=openapi.TYPE_STRING, description='考试名称'),
                    }
                )
            ),
            400: openapi.Response('请求参数不合法'),
            409: openapi.Response('试题已存在'),
            404: openapi.Response('试题不存在'),
        },
        tags=["试卷管理"]
    )
    def post(self, request):
        questions_score = request.data.get('questions', [])
        # [{"question": "27a58581-07cf-4351-b6de-a910b8020221", "score": 20}]
        exam_name = request.data.get('exam_name')
        exam_description = request.data.get('exam_description')
        exam_duration = request.data.get('exam_duration')
        user_id = request.data.get('user_id')
        is_random = request.data.get('is_random')
        status = False

        if not exam_name:
            return api_response(ResponseCode.BAD_REQUEST, "考试名称不能为空")
        if not questions_score:
            return api_response(ResponseCode.BAD_REQUEST, '试题列表不能为空')
        try:
            created_user = User.objects.get(id=user_id)
        except ObjectDoesNotExist:
            return api_response(ResponseCode.NOT_FOUND, '创建人不存在')

        if exam_duration <= 0:
            return api_response(ResponseCode.BAD_REQUEST, '考试时长不能小于等于0')

        if is_random == 0:
            is_random = False
        else:
            is_random = True

        for question_info in questions_score:
            score = question_info.get('score')
            if score <= 0:
                return api_response(ResponseCode.BAD_REQUEST, '分值不能小于等于0')
        # 计算总分
        total_score = sum([question['score'] for question in questions_score])

        paper = Paper.objects.create(
            exam_name=exam_name,
            exam_description=exam_description,
            exam_duration=exam_duration,
            total_score=total_score,
            created_user=created_user,
            status=status,
            is_random=is_random,
        )

        # 添加试题到试卷
        for question_info in questions_score:
            question_id = question_info.get('question')
            score = question_info.get('score')

            try:
                question = Questions.objects.get(id=question_id)
            except ObjectDoesNotExist:
                return api_response(ResponseCode.NOT_FOUND, f'试题不存在')

            if PaperQuestion.objects.filter(paper=paper, question=question).exists():
                return api_response(ResponseCode.CONFLICT, f'试题 {question.topic} 已存在于试卷中')

            PaperQuestion.objects.create(
                paper=paper,
                question=question,
                score=score,
            )

        return api_response(ResponseCode.SUCCESS, '试卷创建成功', {"exam_name": paper.exam_name})


class PaperListView(APIView):
    """
    获取试卷列表接口
    """
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]
    pagination_class = CustomPageNumberPagination

    @swagger_auto_schema(
        operation_description="查询所有试卷列表，支持按考试名称进行筛选",
        manual_parameters=[
            openapi.Parameter('exam_name', openapi.IN_QUERY, description="考试名称", type=openapi.TYPE_STRING),
        ],
        responses={
            200: PaperSerializer(many=True),
            400: "请求参数错误",
            500: "服务器内部错误"
        },
        tags=['试卷管理']
    )
    def get(self, request):
        try:
            exam_name = request.query_params.get("exam_name")
            page = request.query_params.get("pageNo", 1)
            page_size = request.query_params.get("pageSize", 10)

            papers = Paper.objects.all().order_by("exam_name")

            if exam_name:
                papers = papers.filter(exam_name__icontains=exam_name)

            if not papers:
                return api_response(ResponseCode.SUCCESS, "未找到符合条件的试卷", [])

            paginator = CustomPageNumberPagination()
            paginator.page_size = int(page_size)  # 每页的条数
            paginator.page_query_param = 'pageNo'  # 页码的参数名
            paginator.page_size_query_param = 'page_size'  # 每页数据条数的参数名

            result_page = paginator.paginate_queryset(papers, request)
            serializer = PaperSerializer(result_page, many=True)
            paginated_response = paginator.get_paginated_response(serializer.data)

            return api_response(ResponseCode.SUCCESS, '试卷列表获取成功', paginated_response.data)

        except ValidationError as e:
            return api_response(ResponseCode.BAD_REQUEST, f"请求参数错误: {str(e)}")
        except Exception as e:
            return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f"服务器内部错误: {str(e)}")


class PaperDetailView(APIView):
    """
    根据id查询试卷
    """
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

    @swagger_auto_schema(
        operation_description="根据试卷id查询信息",
        manual_parameters=[
            openapi.Parameter('id', openapi.IN_QUERY, description="试卷id", type=openapi.TYPE_STRING),
        ],
        responses={
            200: PaperDetailSerializer(),
            404: "未找到信息",
            500: "服务器内部错误",
        },
        tags=['试卷管理']
    )
    def get(self, request):
        paper_id = request.query_params.get("id")

        try:
            # 根据 ID 获取试卷
            paper = Paper.objects.get(id=paper_id)
        except ObjectDoesNotExist:
            return api_response(ResponseCode.NOT_FOUND, "未找到该试题")

        # 使用 PaperDetailSerializer 来序列化试卷详情
        serializer = PaperDetailSerializer(paper)

        return api_response(ResponseCode.SUCCESS, '试卷详情获取成功', serializer.data)


class DeletePaper(APIView):
    """
        删除试卷
    """
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

    @swagger_auto_schema(
        operation_description="删除试卷接口",
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            properties={
                'ids': openapi.Schema(
                    type=openapi.TYPE_ARRAY,
                    items=openapi.Schema(type=openapi.TYPE_STRING),
                    description='试卷ID列表，删除多个试卷'
                ),
            },
        ),
        responses={
            200: "删除成功",
            400: "未找到该试卷"
        },
        tags=['试卷管理']

    )
    def delete(self, request):
        """
        删除题目接口
        """
        try:
            # 获取请求中的题目 ID 列表
            paper_ids = request.data.get('ids', [])

            if not paper_ids:
                return api_response(ResponseCode.BAD_REQUEST, "请求数据无效，必须提供试卷ID列表")

            # 查找试卷，删除不存在的试卷ID
            paper_to_delete = Paper.objects.filter(id__in=paper_ids)
            if paper_to_delete.count() == 0:
                return api_response(ResponseCode.NOT_FOUND, "未找到题目")

            # 删除找到的题目
            paper_to_delete.delete()

            return api_response(ResponseCode.SUCCESS, "删除成功")
        except Exception as e:
            return api_response(ResponseCode.INTERNAL_SERVER_ERROR, f"服务器内部错误: {str(e)}")


class UpdatePaper(APIView):
    """
    修改试卷接口
    """
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

    @swagger_auto_schema(
        operation_description="修改试卷接口",
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            required=['paper_id', 'exam_name', 'exam_description', 'exam_duration', 'questions'],
            properties={
                'paper_id': openapi.Schema(type=openapi.TYPE_STRING, description='考试id'),
                'exam_name': openapi.Schema(type=openapi.TYPE_STRING, description='考试名称'),
                'exam_description': openapi.Schema(type=openapi.TYPE_STRING, description='考试说明'),
                'exam_duration': openapi.Schema(type=openapi.TYPE_INTEGER, description='考试时长'),
                'user_id': openapi.Schema(type=openapi.TYPE_STRING, description='修改人'),
                'is_random': openapi.Schema(type=openapi.TYPE_INTEGER, description='是否随机排序'),
                'questions': openapi.Schema(
                    type=openapi.TYPE_ARRAY,
                    items=openapi.Schema(
                        type=openapi.TYPE_OBJECT,
                        properties={
                            'question': openapi.Schema(type=openapi.TYPE_STRING, description='试题ID'),
                            'score': openapi.Schema(type=openapi.TYPE_NUMBER, description='分值'),
                        },
                    ),
                    description='试题数组，每个试题包含试题ID和分值',
                )
            },
        ),
        responses={
            200: openapi.Response(
                '修改成功！',
                openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'exam_name': openapi.Schema(type=openapi.TYPE_STRING, description='考试名称'),
                    }
                )
            ),
            400: openapi.Response('请求参数不合法'),
            409: openapi.Response('试题已存在'),
            404: openapi.Response('试题不存在'),
        },
        tags=["试卷管理"]
    )
    def put(self, request):
        questions_score = request.data.get('questions', [])
        paper_id = request.data.get('paper_id')
        exam_name = request.data.get('exam_name')
        exam_description = request.data.get('exam_description')
        exam_duration = request.data.get('exam_duration')
        user_id = request.data.get('user_id')
        is_random = request.data.get('is_random')

        if is_random == 0:
            is_random = False
        else:
            is_random = True
        paper_profile = Paper.objects.filter(id=paper_id).first()

        if paper_profile.status == 1:
            return api_response(ResponseCode.BAD_REQUEST, '试卷已发布，无法修改')

        if not paper_profile:
            return api_response(ResponseCode.NOT_FOUND, '试卷不存在')

        if exam_name != paper_profile.exam_name:
            if Paper.objects.filter(id=exam_name).first():
                return api_response(ResponseCode.CONFLICT, '试卷已存在')
        try:
            update_user = User.objects.get(id=user_id)
        except ObjectDoesNotExist:
            return api_response(ResponseCode.NOT_FOUND, '修改人不存在')

        # 计算总分
        total_score = sum([question['score'] for question in questions_score])

        paper_profile.exam_name = exam_name
        paper_profile.exam_description = exam_description
        paper_profile.exam_duration = exam_duration
        paper_profile.updated_user = update_user
        paper_profile.total_score = total_score
        paper_profile.is_random = is_random
        paper_profile.save()

        try:
            # 开启事务
            with transaction.atomic():
                # 删除试卷中的所有试题
                PaperQuestion.objects.filter(paper=paper_profile).delete()

                # 添加试题到试卷
                for question_info in questions_score:
                    question_id = question_info.get('question')
                    score = question_info.get('score')

                    try:
                        question = Questions.objects.get(id=question_id)
                    except ObjectDoesNotExist:
                        # 抛出异常，事务会自动回滚
                        raise ValueError(f'试题 {question.topic} 不存在')

                    if PaperQuestion.objects.filter(paper=paper_id, question=question).exists():
                        paper = Paper.objects.get(id=paper_id)
                        # 抛出异常，事务会自动回滚
                        raise ValueError(f'试题 {question.topic} 已存在于试卷 {paper.exam_name} 中')

                    PaperQuestion.objects.create(paper=paper_profile, question=question, score=score)

                    serializer = PaperDetailSerializer(paper_profile)

            return api_response(ResponseCode.SUCCESS, '试卷更新成功', serializer.data)

        except ValueError as e:
            # 如果发生异常，回滚事务
            transaction.rollback()
            # 捕获自定义异常，返回错误信息
            return api_response(ResponseCode.BAD_REQUEST, str(e))


class ChangePaper(APIView):
    """
                切换试卷状态
    """
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]  # 需要身份认证才能访问

    @swagger_auto_schema(
        operation_description="切换试卷状态",

        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            required=['paper_id'],
            properties={
                'paper_id': openapi.Schema(type=openapi.TYPE_STRING, description="paper_id"), }
        ),
        responses={200: '切换成功', 400: '切换失败'},
        tags=['试卷管理']
    )
    def put(self, request):
        paper_id = request.data.get('paper_id')
        paper_profile = Paper.objects.filter(id=paper_id).first()
        if not paper_profile:
            return api_response(ResponseCode.NOT_FOUND, '试卷不存在')

        if paper_profile.status:
            paper_profile.status = False
        else:
            paper_profile.status = True

        paper_profile.save()
        return api_response(ResponseCode.SUCCESS, '切换成功')
